<template>
  <div ref="refChart" class="chart"></div>
</template>
<script setup>
import { ref, defineProps, onMounted, onBeforeUnmount, watch } from 'vue';
import * as eCharts from 'echarts';
import {getScale, calculateChartGrid} from './ChartUtils.js';
const refChart = ref(null);

const props = defineProps({
  colorArray: {
    type: Array,
    default: () => [
      {
        top: ['rgba(0, 190, 255, 1)', 'rgba(6, 153, 204, 1)'],
        center: ['rgba(0, 190, 255, 1)', 'rgba(86, 209, 251, 1)', 'rgba(134, 220, 248, 1)'],
        bottom: 'rgba(68, 198, 243, 1)'
      },
      {
        top: ['rgba(17, 155, 254, 1)', 'rgba(6, 131, 220, 1)'],
        center: ['rgba(17, 155, 254, 1)', 'rgba(104, 190, 253, 1)', 'rgba(202, 230, 251, 1)'],
        bottom: 'rgba(149, 207, 248, 1)'
      },
       {
        top: ['rgba(52, 195, 225, 1)', 'rgba(20, 163, 193, 1)'],
        center: ['rgba(52, 195, 225, 1)', 'rgba(78, 206, 233, 1)', 'rgba(109, 218, 242, 1)'],
        bottom: 'rgba(99, 208, 230, 1)'
      },
       {
        top: ['rgba(41, 113, 243, 1)', 'rgba(23, 95, 225, 1)'],
        center: ['rgba(41, 113, 243, 1)', 'rgba(139, 174, 249, 1)', 'rgba(231, 212, 254, 1)'],
        bottom: 'rgba(144, 183, 254, 1)'
      },
      {
        top: ['rgba(191, 208, 255, 1)', 'rgba(147, 165, 217, 1)'],
        center: ['rgba(191, 208, 255, 1)', 'rgba(208, 220, 254, 1)', 'rgba(239, 243, 255, 1)'],
        bottom: 'rgba(213, 224, 255, 1)'
      },
    ]
  },
  data: {
    type: Array,
    default: () => []
  },
  legend: {
    type: Array,
    default: undefined
  },
  barWidth: {
    type: Number,
    default: 16
  },
   /**文字大小 */
  fontSize:{
    type: Number,
    default: 14
  }
});

watch(() => props.data, (v) => {
  if (chart && v.length > 0) {
    const { legend, colorArray } = props;
    let option = getOption(v, legend, colorArray);
    option.series[legend.length * 3 - 1].barGap = '-50%';
    chart.setOption(option, true);
  }
});

let chart;
onMounted(() => {
  const barDom = refChart.value;
  chart = eCharts.init(barDom);
  const { legend, data, colorArray } = props;
  if (data.length > 0) {
    let option = getOption(data, legend, colorArray);
    option.series[legend.length * 3 - 1].barGap = '-50%';
    chart.setOption(option);
  }
  window.addEventListener('resize', resize);
});

/**组件取消挂载之前 */
onBeforeUnmount(()=>{
  window.removeEventListener('resize', resize);
})

/**图表大小变化重新渲染 */
const resize = () =>{
  if (chart) {
    const { legend, data, colorArray } = props;
    let option = getOption(data, legend, colorArray);
    option.series[legend.length * 3 - 1].barGap = '-50%';
    chart.setOption(option, true);
    chart.resize();
  }
}

/**获取默认图表配置 */
const getDefaultOption = ()=>{
  return {
    tooltip: {
      trigger: 'axis',
      show: true,
      formatter: (params) => {
        const items = params.filter(item => item.seriesIndex % 3 === 0);
        const eleStr = createTooltipElement(items);
        return eleStr;
      },
      axisPointer: {
        type: 'shadow'
      }
    },
    grid: calculateChartGrid(undefined,undefined,undefined,56*getScale()),
    textStyle: {
      fontSize: getScale()*props.fontSize,
      color: 'white'
    },
    yAxis: {
      type: 'value',
      axisLine: {
        show: true,
        lineStyle: {
          color: 'white'
        }
      },
      splitLine: {
        show: false
      },
      axisLabel:{
        fontSize: getScale()*props.fontSize
      }
    },
    xAxis: {
      type: '',
      axisLine: {
        show: true,
        lineStyle: {
          color: 'white'
        }
      },
      axisTick: {
        alignWithLabel: true,
        lineStyle: {
          color: 'white'
        }
      },
      axisLabel:{
        fontSize: getScale()*props.fontSize
      }
    },
    series: []
  }
}

/**
 * 深度合并对象
 */
const deepObjectMerge = (targ, source) => {
  const target = targ;
  for (const key in source) {
    if (key.hasOwnProperty) {
      target[key] =
        target[key] && typeof target[key] === 'object'
          ? deepObjectMerge(target[key], source[key])
          : (target[key] = source[key]);
    }
  }
  return target;
};

/**
 * 组装图表series值
 */
const getOption = (data, legendData, colorArray) => {
  let series = [];
  let xAxis = {};
  data.forEach((item, index) => {
    const s = getSerie(item, colorArray[index], legendData[index], index);
    series = series.concat(s);
  });
  let legend = {
    show: true,
    data: legendData,
    bottom: 0,
    icon: 'circle',
    itemWidth: getScale()*12,
    itemHeight: getScale()*12,
    textStyle: {
      color: 'rgba(255,255,255,0.85)',
      fontSize: getScale()*props.fontSize
    }
  };
  xAxis.data = data[0].map(item => item.name);
  const option = deepObjectMerge(getDefaultOption(), {
    xAxis,
    legend,
    series
  });
  return option;
};

const getSerie = (data, colorConfig, name) => {
  const barWidth = getScale()*props.barWidth;
  let _data = data.map(item => item.value);
  return [
    {
      name,
      type: 'pictorialBar',
      barWidth,
      data: _data,
      symbol: 'rect',
      symbolOffset: [barWidth / 2, -barWidth / 3],
      itemStyle: {
        color: getGradientColor(colorConfig.center)
      }
    },
    {
      name,
      type: 'pictorialBar',
      barWidth,
      data: _data,
      symbol: 'circle',
      symbolSize: [barWidth, barWidth * 2 / 3],
      symbolPosition: 'end',
      symbolOffset: [0, -barWidth * 2 / 3],
      itemStyle: {
        color: getGradientColor(colorConfig.top)
      },
      z: 4
    },
    {
      name,
      type: 'pictorialBar',
      barWidth,
      data: _data,
      symbol: 'circle',
      symbolSize: [barWidth, barWidth * 2 / 3],
      symbolPosition: 'start',
      symbolOffset: [-barWidth / 2, 0],
      z: 4,
      itemStyle: {
        color: colorConfig.bottom
      }
    }

  ];
};
/**
 * 获取渐变色配置
 * @params colors 颜色数组 包含起始颜色 结束颜色
 */
const getGradientColor = (colors) => {
  let colorStops;
  if (colors.length === 2) {
    colorStops = [
      { offset: 0, color: colors[0] },
      { offset: 1, color: colors[1] }
    ];
  } else {
    colorStops = [
      { offset: 0, color: colors[0] },
      { offset: 0.9, color: colors[1] },
      { offset: 1, color: colors[2] }
    ];
  }
  return {
    type: 'linear',
    x: 0,
    y: 0,
    x2: 0,
    y2: 1,
    colorStops
  };
};

const createTooltipElement = (items) => {
  let eleStr = '';
  let axisName;
  items.forEach(({ color, data, seriesName, name }) => {
    axisName = name;
    let ele = '<span style="padding: 0.375rem;background: ' + color.colorStops[0].color + ';display: inline-block;border-radius: 0.375rem;"></span><span>&nbsp;&nbsp;' + seriesName + '&nbsp;&nbsp;' + data + '</span><br/>';
    eleStr += ele;
  });
  return '<span>' + axisName + '</span><br/>' + eleStr;
};
</script>
<style lang="less" scoped>
.chart {
  width: 100%;
  height: 100%;
}
</style>
